import GeneralConfig from '../config/general-config';
import Token from '../models/token';
import CommonService from './common-service';
import LocalStorageService from './local-storage-service';
import RememberMeService from './remember-me-service';

export default class TokenService {
  private static tokenField: Token | null;

  static get token(): Token {
    if (!this.tokenField) {
      this.loadToken();
    }

    return this.tokenField!;
  }

  /**
   * Check if the access token exists. True means exists. False means does NOT exist.
   */
  static get hasAccessToken(): boolean {
    return !CommonService.isNullOrUndefinedOrEmptyString(this.token.accessToken);
  }

  /**
   * Gets the active refresh token in string.
   */
  static get activeAccessToken(): string {
    return this.token.accessToken;
  }

  /**
   * Check if the refresh token exists. True means exists. False means does NOT exist.
   */
  static get hasRefreshToken(): boolean {
    return !CommonService.isNullOrUndefinedOrEmptyString(this.token.refreshToken);
  }

  /**
   * Gets the current refresh token in string.
   */
  static get activeRefreshToken(): string {
    return this.token.refreshToken;
  }

  /**
 * Gets current token bearer. It might be null.
 */
  static get bearer(): string {
    return this.token.bearer;
  }

  /**
   * Checks if current access token is expired or not.
   * @returns True means access token is expired. False means access token is still active.
   */
  static get isAccessTokenExpired(): boolean {
    // CommonService.getCurrentDate() returns the local time.
    // The object retrieved from storage is UTC format.
    // Use new Date(this.token.localDateExpired) converts the UTC to local time.
    // That's why we need to create a new date instance for comparion.
    return this.token.localDateExpired!.getTime() < CommonService.getCurrentDate().getTime();
  }

  /**
   * Saves the token based on the data from remote server.
   * @param token The data from remote server. It should contains below properties
   *                  string accessToken
   *                  string refreshToken
   *                  number expiresIn (seconds)
   *                  number requestConsumedSeconds (seconds)
   */
  static saveToken(token: Token): void {
    this.tokenField = token;

    if (RememberMeService.rememberMe) {
      // Removes session data just in case.
      LocalStorageService.removeSessionData(GeneralConfig.localTokenStorageKey);

      // If users checks 'remember me' the data will be saved in local storage.
      LocalStorageService.saveLocalData(GeneralConfig.localTokenStorageKey, this.tokenField);
    } else {
      // Removes the local data just in case.
      LocalStorageService.removeLocalData(GeneralConfig.localTokenStorageKey);

      // If users does NOT check 'remember me' the data will be saved in session storage.
      // Onces user closes the browser the session storage will be auto cleared.
      LocalStorageService.saveSessionData(GeneralConfig.localTokenStorageKey, this.tokenField);
    }
  }

  /**
   * Removes the token from local storage and session storage.
   */
  static removeToken(): void {
    this.tokenField = new Token();

    // Removes the saved token.
    LocalStorageService.removeLocalData(GeneralConfig.localTokenStorageKey);
    LocalStorageService.removeSessionData(GeneralConfig.localTokenStorageKey);
  }

  /**
   * Tries to load the saved token from local storage or session storage based on remembeMe value.
   */
  private static loadToken(): void {
    let tokenJson: any;

    if (RememberMeService.rememberMe) {
      // If user checks 'remember me' the token will be stored in the local storage for next usage.
      tokenJson = LocalStorageService.loadLocalData(GeneralConfig.localTokenStorageKey);
    } else {
      // If user does not check 'remember me' the token will be stored in the session storage.
      tokenJson = LocalStorageService.loadSessionData(GeneralConfig.localTokenStorageKey);
    }

    this.tokenField = tokenJson ? Token.fromJSON(tokenJson) : new Token();
  }
}